﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Device.Location;
using System.Text;
using System.Xml;
using System.Net.Sockets;
using System.Threading;
using Microsoft.Phone.Net.NetworkInformation;

namespace MonitoringFloty_WindowsPhoneClient
{

    public class SocketClient
    {
        Socket _socket = null;
        static ManualResetEvent _clientDone = new ManualResetEvent(false);
        const int TIMEOUT_MILLISECONDS = 5000;
        const int MAX_BUFFER_SIZE = 2048;
        bool connected=false;

        public bool Connected
        {
            get { return connected; }
        }

        public string Connect(int PortNumber)
        {
            string result = String.Empty;
            DnsEndPoint hostEntry = new DnsEndPoint("192.168.0.7", PortNumber);
            _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs();
            socketEventArg.RemoteEndPoint = hostEntry;
            socketEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(delegate(object s, SocketAsyncEventArgs e)
            {
                result = e.SocketError.ToString();
                _clientDone.Set();
            });
            _clientDone.Reset();
            _socket.ConnectAsync(socketEventArg);
            _clientDone.WaitOne(TIMEOUT_MILLISECONDS);
            if (result == "Success")
                connected = true;
            else
                connected = false;
            return result;
        }

        public string Send(string data)
        {
            string response = "Timeout";
            if (_socket != null && connected)
            {
                SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs();
                socketEventArg.RemoteEndPoint = _socket.RemoteEndPoint;
                socketEventArg.UserToken = null;
                socketEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(delegate(object s, SocketAsyncEventArgs e)
                {
                    response = e.SocketError.ToString();
                    _clientDone.Set();
                });
                byte[] payload = Encoding.UTF8.GetBytes(data);
                socketEventArg.SetBuffer(payload, 0, payload.Length);
                _clientDone.Reset();
                _socket.SendAsync(socketEventArg);
                _clientDone.WaitOne(TIMEOUT_MILLISECONDS);
            }
            if(response!="Success")
                connected=false;
            return response;
        }
    }

    public class positionUpdater
    {
        private static positionUpdater instance;

        SocketClient tcpClient;

        public enum testEnum { UniqueID, TelephoneName, OperatorName, OwnString }

        int selectedDeviceInfo = (int)testEnum.UniqueID;

        string ownInfo = String.Empty;

        bool connected = false;

        public string OwnInfo
        {
            get { return ownInfo; }
            set { ownInfo = value; }
        }

        private positionUpdater()
        {
            tcpClient = new SocketClient();
            tcpClient.Connect(2055);
            ownInfo = String.Empty;
        }

        public static positionUpdater Instance
        {
            get
            {
                if (instance == null)
                    instance = new positionUpdater();
                return instance;
            }
        }

        public void updatePosition(GeoCoordinate coords)
        {
            System.Diagnostics.Debug.WriteLine("{0} {1},{2}", Microsoft.Phone.Info.DeviceStatus.DeviceName, coords.Latitude, coords.Longitude);
            string report = generateReport(new positionData { DeviceID = getDeviceID(), Coords = coords }) + "\n";
            if (!tcpClient.Connected)
                tcpClient.Connect(2055);
            tcpClient.Send(report);
        }

        private string getDeviceID()
        {
            switch(this.selectedDeviceInfo)
            {
                case (int)testEnum.OwnString:
                        return this.OwnInfo;
                case (int)testEnum.UniqueID:
                    {
                        object uniqueID;
                        if (Microsoft.Phone.Info.DeviceExtendedProperties.TryGetValue("DeviceUniqueId", out uniqueID) == true)
                        {
                            byte[] bID = (byte[])uniqueID;
                            return Convert.ToBase64String(bID);   // There you go
                        }
                        return String.Empty;
                    }
                case (int)testEnum.TelephoneName:
                    return Microsoft.Phone.Info.DeviceStatus.DeviceName;
                case (int)testEnum.OperatorName:
                    return DeviceNetworkInformation.CellularMobileOperator;
            }
            return String.Empty;
        }

        private string getDeviceNumber()
        {
            return String.Empty;
        }

        private string generateReport(positionData posData)
        {
            StringBuilder sb = new StringBuilder();
            XmlWriterSettings xmlSettings = new XmlWriterSettings() { OmitXmlDeclaration = true };
            using (XmlWriter writer = XmlWriter.Create(sb, xmlSettings))
            {
                //writer.WriteStartDocument();
                writer.WriteStartElement("MobilePositionReport");
                writer.WriteElementString("DeviceID", posData.DeviceID);
                writer.WriteElementString("Latitude", posData.Coords.Latitude.ToString().Replace(".", ","));
                writer.WriteElementString("Longtitude", posData.Coords.Longitude.ToString().Replace(".", ","));
                writer.Flush();
                writer.WriteEndElement();
                //writer.WriteEndDocument();
            }
            return sb.ToString();
        }

        public void setInfoName(testEnum a)
        {
            this.selectedDeviceInfo = (int)a;
        }

        public testEnum getInfoName()
        {
            return (testEnum)this.selectedDeviceInfo;
        }
    }

    public class positionData
    {
        String deviceID;

        public String DeviceID
        {
            get { return deviceID; }
            set { deviceID = value; }
        }
        GeoCoordinate coords;

        public GeoCoordinate Coords
        {
            get { return coords; }
            set { coords = value; }
        }
    }

}
